package cn.ee.dfs.monitor.service.impl;

import cn.ee.dfs.common.entity.QueryRequest;
import cn.ee.dfs.common.utils.AddressUtil;
import cn.ee.dfs.common.utils.RedisTool;
import cn.ee.dfs.monitor.entity.ApiLog;
import cn.ee.dfs.monitor.mapper.ApiLogMapper;
import cn.ee.dfs.monitor.service.IApiLogService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.beans.factory.annotation.Autowired;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static cn.ee.dfs.common.utils.StrUtil.handleParams;

/**
 * 操作日志表 Service实现
 *
 * @author TWJ
 * @date 2019-08-20 19:05:47
 */
@Service
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class ApiLogServiceImpl extends ServiceImpl<ApiLogMapper, ApiLog> implements IApiLogService {


    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private RedisTool redisTool;

    @Override
    public IPage<ApiLog> findApiLogs(QueryRequest request, ApiLog apiLog) {
        LambdaQueryWrapper<ApiLog> queryWrapper = new LambdaQueryWrapper<>();
        // TODO 设置查询条件
        Page<ApiLog> page = new Page<>(request.getPageNum(), request.getPageSize());
        return this.page(page, queryWrapper);
    }

    @Override
    public List<ApiLog> findApiLogs(ApiLog apiLog) {
        LambdaQueryWrapper<ApiLog> queryWrapper = new LambdaQueryWrapper<>();
        // TODO 设置查询条件
        return this.baseMapper.selectList(queryWrapper);
    }

    @Override
    public void saveLog(ProceedingJoinPoint point, ApiLog log, String key) throws JsonProcessingException {
        Map<Object, Object> map = redisTool.hmget(key);
        if (map != null && map.size() > 0) {
            Integer dayCall = (Integer) map.get("dayCall");
            Integer frequency = (Integer) map.get("frequency");
            String serviceName = (String) map.get("serviceName");
            String spName = (String) map.get("spName");

            log.setSpName(spName);
            log.setServiceName(serviceName);

            if (dayCall != null && dayCall > frequency) return;
            String serviceId = (String) map.get("serviceId");
            Object userServiceId = map.get("userServiceId");
            log.setServiceId(Integer.parseInt(serviceId.split(":")[1]));
            log.setUserServiceId((Integer) userServiceId);

            MethodSignature signature = (MethodSignature) point.getSignature();
            Method method = signature.getMethod();
            cn.ee.dfs.common.annotation.ApiLog logAnnotation = method.getAnnotation(cn.ee.dfs.common.annotation.ApiLog.class);
            if (logAnnotation != null) {
                // 注解上的描述
                log.setOperation(logAnnotation.value());
            }
            // 请求的类名
            String className = point.getTarget().getClass().getName();
            // 请求的方法名
            String methodName = signature.getName();
            log.setMethod(className + "." + methodName + "()");
            // 请求的方法参数值
            Object[] args = point.getArgs();
            // 请求的方法参数名称
            LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
            String[] paramNames = u.getParameterNames(method);
            if (args != null && paramNames != null) {
                StringBuilder params = new StringBuilder();
                params = handleParams(params, args, Arrays.asList(paramNames), objectMapper);
                log.setParams(params.toString());
            }
            log.setCreateTime(new Date());
            log.setLocation(AddressUtil.getCityInfo(log.getIp()));
            // 保存系统日志
            this.save(log);
        }
    }

    @Override
    @Transactional
    public void updateApiLog(ApiLog apiLog) {
        this.saveOrUpdate(apiLog);
    }

    @Override
    @Transactional
    public void deleteApiLog(ApiLog apiLog) {
        LambdaQueryWrapper<ApiLog> wapper = new LambdaQueryWrapper<>();
        // TODO 设置删除条件
        this.remove(wapper);
    }

    @Override
    public Integer getCallCount(Integer serviceId, String range) {
        return this.baseMapper.getCallCount(serviceId, range);
    }

    @Override
    public List<Map<String, Object>> findTop10ServiceCallOfYear() {
        return this.baseMapper.findTop10ServiceCallOfYear();
    }

    @Override
    public List<Map<String, Object>> findTop10SysCallOfYear() {
        return this.baseMapper.findTop10SysCallOfYear();
    }

}
